home *** CD-ROM | disk | FTP | other *** search
- /*
- FILENAME
- NewApp.c
-
- DESCRIPTION
- Contains code for all of our message overrides (except the old-application
- compatibility ones.) to implement custom buffering and
- non-standard communications code in a QuickDraw GX printer
- driver. In this code, we write everything to disk (through our
- own buffers) as an extended version 2 PICT file.
-
- COPYRIGHT
- Copyright © 1995 Apple Computer, Inc.
- All rights reserved.
-
- Modification history
- 10/04/95 - David Hayward - Version 1.0.4 modified code so that
- the driver can be build under MPW,
- Metrowerks, and Symantec. In general,
- all that was required to do this was
- to add an inline-assembly jumptable
- and to store all globals off of the
- message manager instance context.
- Also made a few changes so that the
- driver can be rebuilt to support any
- resolution by changing the #defines
- kResolution and kPatStretch in
- "CommonDefines.h"
-
- 06/14/95 - Dave Hersey - Version 1.0.3 to fix a bug in
- CustomBufferingAndIO.c when creating
- high-res PICTs, and to make the size
- of buffers more flexible.
-
- 05/26/95 - Dave Hersey - Version 1.0.2 to add the new 'outp'
- desktop printer resource so that
- paper mismatch and manual feed
- alerts are suppressed. See the
- SD_DefaultDesktopPrinter routine
- for details.
-
- 05/03/95 - Dave Hersey - Version 1.0.1 to fix some minor bugs in
- CustomBufferingAndIO.c.
- Also fixes the following bugs in this file.
-
- * endPict opcodes not always word aligned
- * current buffer not being reset on flush
- * gxWriteData override could not handle a
- simple flush by passing a nil data or
- length parameter.
- * gxFinishSendPage, gxCloseConnection, and
- gxCleanupOpenConnection overrides were
- doing work before forwarding their
- messages which should have been done after
- the forwards.
- 01/14/95 - Dave Hersey - Created from the shell of a hollowed-out
- ImageWriter driver.
- */
-
-
- #include "GlobalData.h"
- #include "NewApp.h"
- #include "CommonDefines.h"
-
-
- // Prototypes for local functions.
- OSErr CreateBuffers ( void ) ;
- OSErr DisposeBuffers ( void ) ;
- OSErr FlushBuffers ( BufferGroupHdl buffGrpHdl ) ;
- OSErr WriteFileData ( void *dataBuffer, long dataLength ) ;
- OSErr WriteEndOfPICTFile ( void ) ;
- OSErr WriteStartOfPICTFile ( void ) ;
- OSErr WriteBlankLines ( long numBlankLinesToDo, gxRectangle *bandRect ) ;
-
-
- /* -----------------------------------------------------------------------
-
- __Startup__ contains our jump table to the overrides.
- This code must be kept in sync with the assembly jump table
- in NewApp.a and the gxOverrideType resources in NewApp.r
-
- ----------------------------------------------------------------------- */
-
- #if defined(__MWERKS__)
- asm void __Startup__(void);
- asm void __Startup__(void)
- {
- DC.L 0 // Reserved for owner count.
-
- // Raster messages
- JMP SD_RasterDataIn // (offset = 4)
-
- // Universal messages
- JMP SD_ImageJob // (offset = 8)
- JMP SD_StartSendPage // (offset = 12)
- JMP SD_FinishSendPage // (offset = 16)
- JMP SD_SetupImageData // (offset = 20)
- JMP SD_OpenConnection // (offset = 24)
- JMP SD_CloseConnection // (offset = 28)
- JMP SD_CleanupOpenConnection // (offset = 32)
- JMP SD_BufferData // (offset = 36)
- JMP SD_FreeBuffer // (offset = 40)
- JMP SD_WriteData // (offset = 44)
- JMP SD_DumpBuffer // (offset = 48)
- JMP SD_DefaultDesktopPrinter // (offset = 52)
-
- RTS // this is needed so __Startup__ symbol works
- }
- #endif
-
-
- /* -----------------------------------------------------------------------
-
- SD_RasterDataIn is an override of gxRasterDataIn. It simply takes the
- bitmap data passed to us, and sends it to the "device" using
- Send_GXBufferData. For this driver, we're being passed 32-bit XRGB
- data (where "X" indicates an unused alpha byte), stripping off the
- unused byte, and sending it to gxBufferData as RGB data.
-
- If we find that we've moved over blank lines, we call WriteBlankLines
- to send RGB bands of white to gxBufferData. If your device supports
- it, it is far more economical to skip the white space, rather than
- image it.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_RasterDataIn (gxOffscreenHdl hOffscreen, gxRectangle *bandRect, gxRectangle *dirtyRect)
- {
- OSErr anErr;
- char lockState;
- gxBitmap *pBitmap;
- unsigned char *XRGBDataPtr, *RGBDataPtr, *scanStart;
- long rowNum, colNum, amtToWrite, numBlankLinesToDo;
- Ptr baseAddr;
- DriverGlobalsHdl drvrGlobalsHdl;
-
- #pragma unused (dirtyRect)
-
- // get the globals from the instance handler context
- drvrGlobalsHdl = GetGlobals();
-
- // Update the status display to indicate that we're sending data to the "printer."
- anErr = GXReportStatus(kTransmissionStatID, kSendingPartStatIdx);
- require(anErr == noErr, ReportStatus_Failed);
-
-
- // Write some blank lines if we need to.
- numBlankLinesToDo = (bandRect->top >>16) - (*drvrGlobalsHdl)->lastYPos;
- if (numBlankLinesToDo > 0)
- {
- anErr = WriteBlankLines(numBlankLinesToDo, bandRect);
- nrequire(anErr, WriteBlankLines_Failed);
- }
-
- // Make sure the offscreen bitmap is locked down, and then repackage the
- // data. To save space, we're converting the XRGB data to RGB data in
- // the same imaging buffer that was passed to us.
- lockState = HGetState((Handle) hOffscreen);
- HLockHi((Handle) hOffscreen);
-
- pBitmap = &(*hOffscreen)->thePlanes[0].theBits;
- RGBDataPtr = XRGBDataPtr = (unsigned char *) ((unsigned long) pBitmap->image + (unsigned long) ((bandRect->left >>16) * 4));
- baseAddr = (Ptr) RGBDataPtr;
-
-
- // Convert all data in this raster bitmap to 24-bit RGB. XRGBData
- // points to the next byte of unconverted data, and RGBDataPtr
- // points to the next place to store the converted RGB data.
-
- for (rowNum = (bandRect->top >>16); rowNum < (bandRect->bottom >>16); rowNum++)
- {
- scanStart = XRGBDataPtr;
-
- for (colNum = (bandRect->left >>16); colNum < (bandRect->right >>16); colNum++)
- {
- ++XRGBDataPtr; // skip those dang alphas!
- *RGBDataPtr = *XRGBDataPtr; // copy Red component
- ++RGBDataPtr;
- ++XRGBDataPtr;
- *RGBDataPtr = *XRGBDataPtr; // copy Green component
- ++RGBDataPtr;
- ++XRGBDataPtr;
- *RGBDataPtr = *XRGBDataPtr; // copy Blue component
- ++RGBDataPtr;
- ++XRGBDataPtr;
- }
-
- if (rowNum == (bandRect->top >>16)) // 1st row? Store some things for later.
- {
- (*drvrGlobalsHdl)->pixMapRowBytes = (long) XRGBDataPtr - (long) baseAddr;
- (*drvrGlobalsHdl)->pixMapBounds.bottom += (bandRect->bottom >>16) - (bandRect->top >>16);
- (*drvrGlobalsHdl)->pixMapBounds.right = (bandRect->right >>16) - (bandRect->left >>16);
- }
-
- // Bump XRGBDataPtr to the start of the next scan line.
- XRGBDataPtr = scanStart + (pBitmap->rowBytes & 0x7FFF);
- }
-
- // Write out the data for this band.
-
- amtToWrite = (long) RGBDataPtr - (long) baseAddr;
- anErr = Send_GXBufferData(baseAddr, amtToWrite, gxNoBufferOptions);
-
- // Reset the handle's lock on the way out, and update our
- // lastYPos variable.
-
- HSetState((Handle) hOffscreen, lockState);
-
- WriteBlankLines_Failed:
- ReportStatus_Failed:
- (*drvrGlobalsHdl)->lastYPos = (bandRect->bottom >>16) +1;
-
- return anErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- SD_DefaultDesktopPrinter is an override of gxDefaultDesktopPrinter.
- It adds an 'outp' resource to the newly created desktop printer.
- This resource was introduced for QuickDraw GX 1.1, and allows us to
- specify that we don't have paper trays, so paper mismatches and manual
- feed alerts should be suppressed.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_DefaultDesktopPrinter(Str31 dtpName)
- {
- OSErr anErr;
- gxDriverOutputSettingsHdl resHdl;
-
- // Forward the message, so the desktop printer creation is completed.
-
- anErr = Forward_GXDefaultDesktopPrinter(dtpName);
- nrequire(anErr, Failed_DefaultDesktopPrinter);
-
-
- // Create a gxDriverOutputSettingsHdl that has the outputSettings
- // field cleared, rather than set to gxCanConfigureTrays.
-
- resHdl = (gxDriverOutputSettingsHdl) NewHandleSysClear(sizeof(gxDriverOutputSettingsHdl));
- require(resHdl, Failed_NewHandleSysClear);
-
-
- // Add the handle to our desktop printer, and then dispose of it.
-
- anErr = GXWriteDTPData(dtpName, gxDriverOutputType, gxDriverOutputTypeID, (Handle) resHdl);
- nrequire(anErr, Failed_WriteDTPResource);
-
- DisposeHandle((Handle) resHdl);
-
- Failed_WriteDTPResource:
- Failed_NewHandleSysClear:
- Failed_DefaultDesktopPrinter:
-
- return anErr;
- }
-
- /* -----------------------------------------------------------------------
-
- SD_OpenConnection is an override for gxOpenConnection. In this routine
- we allocate our custom buffer structures and forward the message to the
- default gxOpenConnection handler. Since we specify customIO in our
- 'iobm' resource, no connection is actually opened.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_OpenConnection()
- {
- OSErr anErr;
-
- // Create our buffers, then forward the message.
-
- anErr = CreateBuffers();
-
- if (!anErr)
- anErr = Forward_GXOpenConnection();
- else
- GXCleanupOpenConnection();
-
- return anErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- SD_CloseConnection is an override for gxCloseConnection. In this
- routine we forward the message to the default gxCloseConnection
- handler and dispose of our custom buffer structures.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_CloseConnection()
- {
- OSErr anErr;
-
- // Forward the message and dispose of our buffers.
-
- anErr = Forward_GXCloseConnection();
- DisposeBuffers();
-
- return anErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- SD_CleanupOpenConnection is an override for gxCleanupOpenConnection.
- In this routine we forward the message and dispose of our data
- structures that might have been allocated before we got an error in
- our gxOpenConnection code.
-
- ----------------------------------------------------------------------- */
-
- void SD_CleanupOpenConnection()
- {
- // Forward the message and dispose of our buffers (if any).
-
- Forward_GXCleanupOpenConnection();
- DisposeBuffers();
- }
-
-
- /* -----------------------------------------------------------------------
-
- SD_BufferData is an override for the gxBufferData message. To support
- our custom buffering code, we perform a total override of this message,
- fill up the next available buffer with the data. We'll store data and,
- if necessary, flush buffers until all of the passed data has been
- processed.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_BufferData(Ptr data, long length, long bufferOptions) // only override for custom buffering
- {
- OSErr anErr = noErr;
- register char *pData = (char *) data;
- register BufferEntryPtr buffPtr;
- short idx, curBuff;
- Boolean foundAFreeBuffer;
- long dataLeftToStore = length;
- char hdlState;
- DriverGlobalsHdl drvrGlobalsHdl;
- BufferGroupHdl buffGrpHdl;
-
- #pragma unused(bufferOptions)
-
- // get the globals from the instance handler context
- drvrGlobalsHdl = GetGlobals();
- buffGrpHdl = (**drvrGlobalsHdl).buffer;
-
- // Lock the buffer group.
- hdlState = HGetState((Handle) buffGrpHdl);
- HLockHi((Handle) buffGrpHdl);
-
- // While there's no error, and more data to store, process data.
- while (!anErr && (dataLeftToStore > 0))
- {
- // Fill the current buffer with data and indicate that the buffer is dirty.
-
- curBuff = (*buffGrpHdl)->curBuff;
- buffPtr = &(*buffGrpHdl)->buff[curBuff];
-
- while ((dataLeftToStore > 0) && (buffPtr->curOffset < (*buffGrpHdl)->bufferSize))
- {
- // Move the data to our buffer.
- (*buffPtr->printBuffer)->data[buffPtr->curOffset] = *pData;
- ++(buffPtr->curOffset);
- ++pData;
- --dataLeftToStore;
- }
-
- buffPtr->bufferIsDirty = true;
-
-
- // If dataLeftToStore > 0, it means that we've filled the current buffer,
- // and we need another. Find a free one.
-
- if (dataLeftToStore > 0)
- {
- foundAFreeBuffer = false;
-
- // If we can find another buffer that's not dirty, we've found a
- // buffer we can store data in. By specifying numBuffers -1 below,
- // we avoid checking the current buffer, which we know is dirty.
- for (idx = 0; idx < ((*buffGrpHdl)->numBuffers -1); idx++)
- {
- // Search up from the last buffer we checked,
- // wrapping around if necessary.
-
- ++curBuff;
- if (curBuff >= (*buffGrpHdl)->numBuffers)
- curBuff = 0;
-
- buffPtr = &(*buffGrpHdl)->buff[curBuff];
-
- if (!buffPtr->bufferIsDirty)
- {
- foundAFreeBuffer = true;
- break;
- }
- }
-
- // If there are no free buffers, flush them all and use buffer 0.
- if (!foundAFreeBuffer)
- {
- anErr = FlushBuffers(buffGrpHdl);
- curBuff = 0;
- }
-
- // Whatever our current buffer is, store it in our buffer
- // structure.
- (*buffGrpHdl)->curBuff = curBuff;
- }
- }
-
- // Restore the state of the buffer group handle.
- HSetState((Handle) buffGrpHdl, hdlState);
- return anErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- SD_FreeBuffer is an override for the gxFreeBuffer message. You only
- need to override this message if you're doing asynchronous I/O. Since
- we're not, this is only here as a reminder for you. It does nothing
- but forward the message to the default implementation of gxFreeBuffer.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_FreeBuffer(gxPrintingBuffer *theBuffer)
- {
- return Forward_GXFreeBuffer(theBuffer);
- }
-
-
- /* -----------------------------------------------------------------------
-
- SD_WriteData is an override for gxWriteData. Here, we flush our custom
- buffers and then write the passed data, if any, to the output file
- using our custom I/O routine, WriteFileData.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_WriteData(Ptr data, long length)
- {
- OSErr anErr;
- DriverGlobalsHdl drvrGlobalsHdl;
- BufferGroupHdl buffGrpHdl;
-
- // get the globals from the instance handler context
- drvrGlobalsHdl = GetGlobals();
- buffGrpHdl = (**drvrGlobalsHdl).buffer;
-
- // Flush the buffers, then do the actual write.
- anErr = FlushBuffers(buffGrpHdl);
- if (!anErr && (data != nil) && (length > 0))
- anErr = WriteFileData(data, length);
-
- return anErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- SD_DumpBuffer is an override for gxDumpBuffer. Here, we write the
- passed data to the output file using our custom I/O routine,
- WriteFileData.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_DumpBuffer(gxPrintingBuffer *theBuffer)
- {
- if (theBuffer->size != 0)
- return WriteFileData(theBuffer->data, theBuffer->size);
- else
- return noErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- SD_ImageJob is an override for gxImageJob. Here, we create and
- initialize global data that we'll use during imaging.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_ImageJob(gxSpoolFile theSpoolFile, long *closeOptions)
- {
- OSErr anErr;
- FSSpec anFSSpec;
- short vRefNum;
- long dirID, itemSize;
- gxJobInfo jobInfo;
- Str255 fileName;
- DriverGlobalsHdl drvrGlobalsHdl;
-
- // Create and store a handle for our global data.
- anErr = CreateGlobals();
- drvrGlobalsHdl = GetGlobals();
-
- // Now, do some more initialization for the first file we'll write to.
-
- if (!anErr)
- {
- // Determine the name of this document, and append ", Page " to it.
- // We'll use this when we create PICT files. Again, the string
- // should really come from a resource file, for localization
- // reasons.
-
- itemSize = sizeof(gxJobInfo);
- anErr = GetCollectionItem(GXGetJobCollection(GXGetJob()),
- gxJobTag, gxPrintingTagID,
- &itemSize, &jobInfo);
-
- nrequire(anErr, GetCollectionItemFailed);
-
- if (jobInfo.documentName[0] > 22) // If necessary, crop file name so we
- jobInfo.documentName[0] = 22; // have room for our page # stuff.
-
- BlockMove(&jobInfo.documentName[1], &fileName[1], (long) jobInfo.documentName[0]);
- BlockMove(", Page ", &fileName[jobInfo.documentName[0] +1], 7);
-
- // Now make an FSSpec for this file.
-
- FindFolder(kOnSystemDisk, kDesktopFolderType, kCreateFolder, &vRefNum, &dirID);
- fileName[0] = jobInfo.documentName[0] +7;
- FSMakeFSSpec(vRefNum, dirID, fileName, &anFSSpec);
- BlockMove(&anFSSpec, &(*drvrGlobalsHdl)->fileLocation, sizeof(FSSpec));
-
- // Set the number of pages we've imaged to 0.
- (*drvrGlobalsHdl)->pagesImaged = 0;
-
- // With our global data initialized, it's time to forward the
- // gxImageJob message so that the job is processed.
- anErr = Forward_GXImageJob(theSpoolFile, closeOptions);
-
- // All done imaging! Close the last file, if it's still open,
- // and flush the volume so that we get the changes out to disk
- // faster.
-
- if ((*drvrGlobalsHdl)->curFileRefNum)
- FSClose((*drvrGlobalsHdl)->curFileRefNum);
-
- FlushVol("\p", (*drvrGlobalsHdl)->fileLocation.vRefNum);
-
- GetCollectionItemFailed:
-
- // However we get here, dispose of the global data we allocated above.
-
- DisposeGlobals();
- }
-
- return anErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- SD_StartSendPage is an override for gxStartSendPage. Here, we close
- the current file (if any) and open a new one for the next page. This
- way, we're able to create a PICT file for each page of a document.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_StartSendPage(gxFormat pageFormat)
- {
- OSErr anErr;
- char numStr[11], maxChars, nextChar;
- long numLen;
- DriverGlobalsHdl drvrGlobalsHdl;
-
- // get the globals from the instance handler context
- drvrGlobalsHdl = GetGlobals();
-
- // Close current file, if any.
- HLockHi((Handle) drvrGlobalsHdl);
- if ((*drvrGlobalsHdl)->curFileRefNum)
- {
- FSClose((*drvrGlobalsHdl)->curFileRefNum);
- (*drvrGlobalsHdl)->curFileRefNum = (short) nil;
- }
-
- // Bump the number of pages imaged, and use that in the
- // filename for the next page. We started pagesImaged at
- // 0, so the first filename will have a 1 appended to it.
-
- (*drvrGlobalsHdl)->lastYPos = 0;
- ++(*drvrGlobalsHdl)->pagesImaged;
-
- NumToString((*drvrGlobalsHdl)->pagesImaged, (void *) numStr);
- numLen = (unsigned long) numStr[0];
- maxChars = 31 -numLen;
-
- if ((*drvrGlobalsHdl)->fileLocation.name[0] > maxChars)
- (*drvrGlobalsHdl)->fileLocation.name[0] = maxChars;
-
- nextChar = (*drvrGlobalsHdl)->fileLocation.name[0] +1;
- BlockMove(&numStr[1], &(*drvrGlobalsHdl)->fileLocation.name[nextChar], numLen);
- (*drvrGlobalsHdl)->fileLocation.name[0] += numLen;
-
-
- // Create a new file for this page, recklessly replacing any
- // existing file with that name.
- FSpDelete(&(*drvrGlobalsHdl)->fileLocation);
- anErr = FSpCreate(&(*drvrGlobalsHdl)->fileLocation, kFileCreator, kFileType, smSystemScript);
-
- // Open the new file, and write the beginning of the PICT file.
- if (!anErr)
- anErr = FSpOpenDF(&(*drvrGlobalsHdl)->fileLocation, fsCurPerm, &(*drvrGlobalsHdl)->curFileRefNum);
- if (!anErr)
- anErr = WriteStartOfPICTFile();
-
-
- // Initialize this page's PICT's pixmap's bounds to (0,0,0,0).
- (*drvrGlobalsHdl)->pixMapBounds.top = 0;
- (*drvrGlobalsHdl)->pixMapBounds.left = 0;
- (*drvrGlobalsHdl)->pixMapBounds.bottom = 0;
- (*drvrGlobalsHdl)->pixMapBounds.right = 0;
-
-
- // Strip the page number we just added from the file name in our globals.
- // This way, we won't have it when it comes time to set up the file name
- // for the next page.
- (*drvrGlobalsHdl)->fileLocation.name[0] -= numLen;
- HUnlock((Handle) drvrGlobalsHdl);
-
-
- // Finally, forward gxStartSendPage so that GX and any overrides can do
- // whatever they need to do.
-
- if (!anErr)
- anErr = Forward_GXStartSendPage(pageFormat);
-
- return anErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- SD_FinishSendPage is an override for gxFinishSendPage. Here, we
- forward the gxFinishPage message and write out the end of the PICT
- file we created in SD_StartSendPage.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_FinishSendPage()
- {
- OSErr anErr1, anErr2;
-
- // Forward the gxFinishPage message and write out the
- // remainder of this page's PICT file.
-
- anErr1 = Forward_GXFinishSendPage();
- anErr2 = WriteEndOfPICTFile();
-
- return (anErr1)? anErr1: anErr2;
- }
-
-
- /* -----------------------------------------------------------------------
-
- SD_SetupImageData is an override for gxSetupImageData. Here, we
- forward the gxSetupImageData message and store the resolution for
- the PICTs we'll create.
-
- ----------------------------------------------------------------------- */
-
- OSErr SD_SetupImageData(gxRasterImageDataHdl hImageData)
- {
- OSErr anErr;
- DriverGlobalsHdl drvrGlobalsHdl;
-
- // get the globals from the instance handler context
- drvrGlobalsHdl = GetGlobals();
-
- // Do the default setup.
-
- anErr = Forward_GXSetupImageData(hImageData);
-
- // Set up our PICT resolution based on the information in the
- // gxRasterImageDataHdl that we're passed.
-
- (*drvrGlobalsHdl)->hRes = (*hImageData)->hImageRes;
- (*drvrGlobalsHdl)->vRes = (*hImageData)->vImageRes;
-
- return (anErr);
- }
-
-
- /* -----------------------------------------------------------------------
-
- CreateBuffers is the routine which creates and initializes our custom
- buffers.
-
- ----------------------------------------------------------------------- */
-
- static OSErr CreateBuffers()
- {
- OSErr anErr;
- long thisBig;
- DriverGlobalsHdl drvrGlobalsHdl;
- BufferGroupHdl buffGrpHdl;
-
- // get the globals from the instance handler context
- drvrGlobalsHdl = GetGlobals();
-
- thisBig = sizeof(BufferGroup) +
- (sizeof(BufferEntry) * (kNumBuffs -1));
-
- // Create one handle for our buffer "group" and then individual handles for
- // each buffer in the group.
-
- buffGrpHdl = (BufferGroupHdl) TempNewHandle(thisBig, &anErr);
-
- if (!anErr)
- {
- short idx;
- Size ourBufferSize, growDummy;
-
- // Initialize the buffer structure and store the buffer group in
- // our instance context so we can get it later.
-
- (**buffGrpHdl).numBuffers = kNumBuffs;
- (**buffGrpHdl).curBuff = 0;
-
- // We'll make kNumBuffs buffers that use a total of kMaxRAMToUse
- // or kBuffRAMPercentage of the largest available block, whichever
- // is less.
-
- ourBufferSize = (TempMaxMem(&growDummy) * kBuffRAMPercentage) / 100;
- ourBufferSize = (ourBufferSize < kMaxRAMToUse)? ourBufferSize: kMaxRAMToUse;
- ourBufferSize /= kNumBuffs;
-
- // Store the buffer size. We subtract the size of a gxPrintingBuffer, since
- // the bytes occupied by the gxPrintingBuffer structure are not actually
- // available for storing data. (Look at the structure if this sounds
- // confusing.)
-
- (**buffGrpHdl).bufferSize = ourBufferSize - sizeof(gxPrintingBuffer);
-
- for (idx = (**buffGrpHdl).numBuffers; idx > 0; idx--)
- {
- OSErr tempErr = anErr;
-
- (**buffGrpHdl).buff[idx -1].bufferIsDirty = false;
- (**buffGrpHdl).buff[idx -1].curOffset = 0;
- (**buffGrpHdl).buff[idx -1].printBuffer
- = (gxPrintingBuffer **) TempNewHandle(ourBufferSize, &tempErr);
-
- if (!anErr) anErr = tempErr; // Don't worry about errors until we leave.
- // The caller will send GXCleanupOpenConnection
- // if we fail, and that will call DisposeBuffers.
- }
-
- for (idx = (**buffGrpHdl).numBuffers; idx > 0; idx--)
- {
- if ((**buffGrpHdl).buff[idx -1].printBuffer != nil)
- HLock( (Handle)(**buffGrpHdl).buff[idx -1].printBuffer );
- }
-
- (**drvrGlobalsHdl).buffer = buffGrpHdl;
- }
-
- return anErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- DisposeBuffers is the routine which disposes of our custom buffers.
-
- ----------------------------------------------------------------------- */
-
- static OSErr DisposeBuffers ( void )
- {
- DriverGlobalsHdl drvrGlobalsHdl;
- BufferGroupHdl buffGrpHdl;
-
- // get the globals from the instance handler context
- drvrGlobalsHdl = GetGlobals();
- buffGrpHdl = (**drvrGlobalsHdl).buffer;
-
- // Have we set up them there buffers? Then erradicate 'em.
- if ( buffGrpHdl != nil )
- {
- short idx;
-
- // Dispose of any allocated buffers.
-
- for (idx = (**buffGrpHdl).numBuffers; idx > 0; idx--)
- {
- if ((**buffGrpHdl).buff[idx -1].printBuffer != nil)
- DisposeHandle( (Handle) (**buffGrpHdl).buff[idx -1].printBuffer );
- }
-
- DisposeHandle( (Handle)buffGrpHdl );
-
- // Indicate that we have no buffers.
-
- (**drvrGlobalsHdl).buffer = nil;
- }
-
- return noErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- FlushBuffers is the routine which flushes our custom buffers. To do
- this, it cycles through each one to see if there's data in it. If so,
- it sends gxDumpBuffer for the buffer, followed by gxFreeBuffer.
-
- ----------------------------------------------------------------------- */
-
- static OSErr FlushBuffers(BufferGroupHdl buffGrpHdl)
- {
- OSErr anErr = noErr;
- short idx;
- char hdlState;
-
- // Lock the buffer group.
-
- hdlState = HGetState((Handle) buffGrpHdl);
- HLockHi((Handle) buffGrpHdl);
-
- // Send gxDumpBuffer and gxFreeBuffer for each buffer with data in it.
-
- for (idx = 0; idx < (*buffGrpHdl)->numBuffers; idx++)
- {
- if ((*buffGrpHdl)->buff[idx].bufferIsDirty)
- {
- // gxDumpBuffer will look at printbuffer.size to see how much
- // data to write out. Set it to the current offset, which just
- // happens to equal the number of bytes we've stored in the buffer.
-
- (*(*buffGrpHdl)->buff[idx].printBuffer)->size =
- (*buffGrpHdl)->buff[idx].curOffset;
-
-
- // Send gxDumpBuffer and gxFreeBuffer for this buffer.
-
- anErr = Send_GXDumpBuffer(*(*buffGrpHdl)->buff[idx].printBuffer);
-
- if (!anErr)
- anErr = Send_GXFreeBuffer(*(*buffGrpHdl)->buff[idx].printBuffer);
-
-
- // Clear the buffer's dirty flag and reset its data offset.
-
- (*buffGrpHdl)->buff[idx].bufferIsDirty = false;
- (*buffGrpHdl)->buff[idx].curOffset = 0;
- }
- }
-
- (*buffGrpHdl)->curBuff = 0;
-
- // Restore the state of the buffer group handle.
- HSetState((Handle) buffGrpHdl, hdlState);
-
- return anErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- WriteFileData is a routine that writes the passed data to a file whose
- reference ID is stored in our global data.
-
- ----------------------------------------------------------------------- */
-
- static OSErr WriteFileData(void *dataBuffer, long dataLength)
- {
- long amtToWrite = dataLength;
- DriverGlobalsHdl drvrGlobalsHdl;
-
- // get the globals from the instance handler context
- drvrGlobalsHdl = GetGlobals();
-
- // Write some data to our file.
- return FSWrite((*drvrGlobalsHdl)->curFileRefNum, &amtToWrite, dataBuffer);
- }
-
-
- /* -----------------------------------------------------------------------
-
- WriteStartOfPICTFile is a routine that writes out the start of an
- extended version 2 PICT that only contains a clip and a pixmap. In
- this routine we write out all the data up to the pixmap data. However,
- since we won't know things like the bounds and rowbytes until later,
- we simply write out zeroes now, and update everything when we're done
- imaging this page. We do the updating in the routine
- WriteEndOfPICTFile.
-
- ----------------------------------------------------------------------- */
-
- static OSErr WriteStartOfPICTFile ( void )
- {
- OSErr anErr;
- Ptr dataPtr;
-
- // We need to write out the 512 unused bytes that every PICT file
- // contains, plus 122 bytes that comprise the header and information
- // that precedes the pixel data in our pixmap. Since we do this at
- // the start of the page, when SD_DumpBuffer and SD_WriteData write
- // data to the file, they'll actually be filling out the pixel data
- // in our PICT's pixmap.
- //
- // Anyway, create a clear pointer that's big enough to hold all the
- // data that precedes our pixmap's pixels. If there are no errors,
- // write it out via our gxBufferData override. When done, dispose
- // of the pointer we used.
-
- dataPtr = NewPtrClear(512 +122);
-
- if (!(anErr = MemError()))
- {
- anErr = Send_GXBufferData(dataPtr, 512 +122, gxNoBufferOptions);
- DisposePtr(dataPtr);
- }
-
- return anErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- WriteEndOfPICTFile is a routine that writes out the end of an
- extended version 2 PICT that only contains a clip and a pixmap. It
- also updates the beginning of the PICT, with information about the
- pixmap's bounds and so forth. The beginning of the PICT was written
- out with the WriteStartOfPICTFile routine.
-
- Writing out the end of the PICT simply involves writing out the end-
- of-PICT opCode 0x00FF. Most of the work done in this routine has to
- do with updating the start-of-PICT data that we already wrote out.
-
- ----------------------------------------------------------------------- */
-
- static OSErr WriteEndOfPICTFile ( void )
- {
- OSErr anErr;
- Fixed hRes, vRes, hResScale, vResScale;
- short finalPictData;
- short initialPictData[61], curFileRefNum;
- long index = 0, pictSize;
- Rect drawRect, a72dpiDrawRect;
- DriverGlobalsHdl drvrGlobalsHdl;
-
- // get the globals from the instance handler context
- drvrGlobalsHdl = GetGlobals();
-
- // Get the horizontal and vertical resolutions that we imaged
- // at, along with the scaling necessary to apply to 72 dpi
- // viewing rectangles for this image.
- hRes = (*drvrGlobalsHdl)->hRes;
- vRes = (*drvrGlobalsHdl)->vRes;
- hResScale = FixRatio(72, hRes >>16); // FixRatio(hRes >>16, 72);
- vResScale = FixRatio(72, vRes >>16); // FixRatio(vRes >>16, 72);
-
- // Get the pixmap's native bounds, and calculate the correct
- // viewing rectangle for 72 dpi. We pin the top/left corner
- // of each rectangle to 0,0 for convenience.
- drawRect = (*drvrGlobalsHdl)->pixMapBounds;
- OffsetRect(&drawRect, -drawRect.left, -drawRect.top);
- a72dpiDrawRect.top = a72dpiDrawRect.left = 0;
- a72dpiDrawRect.bottom = (FixMul(ff(drawRect.bottom), vResScale) >>16);
- a72dpiDrawRect.right = (FixMul(ff(drawRect.right), hResScale) >>16);
-
- // Flush our buffers. (Yes, since we're doing our own buffer
- // management, we could just call FlushBuffers, but this is how
- // you'd do it otherwise.)
- anErr = Send_GXWriteData(nil, 0);
- nrequire(anErr, FlushBuffersFailed);
-
- // Get the current file's refNum. Since we flushed the buffers,
- // we can go back and see how big the PICT is. Do so.
-
- curFileRefNum = (*drvrGlobalsHdl)->curFileRefNum;
- anErr = GetEOF(curFileRefNum, &pictSize);
- nrequire(anErr, GetEOFFailed);
-
- // If necessary, add a $00 to word align the endPict opcode.
- if ((pictSize & 1) != 0)
- {
- finalPictData = 0;
- anErr = Send_GXWriteData((Ptr) &finalPictData, 1);
- nrequire(anErr, WordAlignFailed);
- ++pictSize;
- }
-
- // Write the endPict opcode.
- finalPictData = 0x00FF;
- anErr = Send_GXWriteData((Ptr) &finalPictData, 2);
- nrequire(anErr, SendFinalDataFailed);
-
- // Now, we're ready to update the information that precedes
- // the pixmap data. Set our file position to 512 bytes from
- // the start. That puts us just past the obsolete PICT header
- // that we're required to include.
- anErr = SetFPos(curFileRefNum, fsFromStart, 512);
- nrequire(anErr, SetFPosFailed);
-
- // Store the low word of picsize.
- initialPictData[index] = pictSize & 0xFFFF;
- ++index;
-
- // Store the picFrame at 72 dpi.
- initialPictData[index] = a72dpiDrawRect.top;
- ++index;
- initialPictData[index] = a72dpiDrawRect.left;
- ++index;
- initialPictData[index] = a72dpiDrawRect.bottom;
- ++index;
- initialPictData[index] = a72dpiDrawRect.right;
- ++index;
-
- // Store the pict version opcode ($0011).
- initialPictData[index] = 0x0011;
- ++index;
-
- // Store the pict version ($02FF).
- initialPictData[index] = 0x02FF;
- ++index;
-
- // Store the header opcode ($0C00).
- initialPictData[index] = 0x0C00;
- ++index;
-
- // Store the header version (-2).
- initialPictData[index] = -2;
- ++index;
-
- // Store the reserved word (0).
- initialPictData[index] = 0;
- ++index;
-
- // Store the native horizontal resolution (Fixed) of the source data.
-
- initialPictData[index] = hRes >>16;
- ++index;
- initialPictData[index] = hRes & 0xFFFF;
- ++index;
-
- // Store the native vertical resolution (Fixed) of the source data.
-
- initialPictData[index] = vRes >>16;
- ++index;
- initialPictData[index] = vRes & 0xFFFF;
- ++index;
-
- // Store the native source rectangle.
-
- initialPictData[index] = drawRect.top;
- ++index;
- initialPictData[index] = drawRect.left;
- ++index;
- initialPictData[index] = drawRect.bottom;
- ++index;
- initialPictData[index] = drawRect.right;
- ++index;
-
- // Store the reserved longword (0L).
-
- initialPictData[index] = 0;
- ++index;
- initialPictData[index] = 0;
- ++index;
-
- // Store the clip opcode (1).
-
- initialPictData[index] = 1;
- ++index;
-
- // Store the size of the clip region data (10).
-
- initialPictData[index] = 10;
- ++index;
-
- // Store the clip rectangle.
-
- initialPictData[index] = drawRect.top;
- ++index;
- initialPictData[index] = drawRect.left;
- ++index;
- initialPictData[index] = drawRect.bottom;
- ++index;
- initialPictData[index] = drawRect.right;
- ++index;
-
- // Store the opBitsRect opcode ($009A).
-
- initialPictData[index] = 0x009A;
- ++index;
-
- // Store the pixmap's baseAddr placeholder (always $000000FF).
-
- initialPictData[index] = 0x0000;
- ++index;
- initialPictData[index] = 0x00FF;
- ++index;
-
- // Store the rowBytes (high bit must be set for a pixmap).
-
- initialPictData[index] = (*drvrGlobalsHdl)->pixMapRowBytes | 0x8000;
- ++index;
-
- // Store the pixmap bounds at source resolution.
-
- initialPictData[index] = drawRect.top;
- ++index;
- initialPictData[index] = drawRect.left;
- ++index;
- initialPictData[index] = drawRect.bottom;
- ++index;
- initialPictData[index] = drawRect.right;
- ++index;
-
- // Store the pixmap version (0).
-
- initialPictData[index] = 0;
- ++index;
-
- // Store the pixmap packing type (2 == we dropped pad bytes).
-
- initialPictData[index] = 2;
- ++index;
-
- // Store the packing size (0L).
-
- initialPictData[index] = 0;
- ++index;
- initialPictData[index] = 0;
- ++index;
-
- // Store the horizontal resolution (Fixed) of the source data.
-
- initialPictData[index] = hRes >>16;
- ++index;
- initialPictData[index] = hRes & 0xFFFF;
- ++index;
-
- // Store the vertical resolution (Fixed) of the source data.
-
- initialPictData[index] = vRes >>16;
- ++index;
- initialPictData[index] = vRes & 0xFFFF;
- ++index;
-
- // Store the pixelType (direct == 16).
-
- initialPictData[index] = 16;
- ++index;
-
- // Store the pixelSize (32 (packed to 24) bits per pixel).
-
- initialPictData[index] = 32;
- ++index;
-
- // Store the pixel component count (3).
-
- initialPictData[index] = 3;
- ++index;
-
- // Store the pixel component size (8).
-
- initialPictData[index] = 8;
- ++index;
-
- // Store the offset to next plane (0).
-
- initialPictData[index] = 0;
- ++index;
- initialPictData[index] = 0;
- ++index;
-
- // Store the ctSeed (0L).
-
- initialPictData[index] = 0;
- ++index;
- initialPictData[index] = 0;
- ++index;
-
- // Store the ctFlags (0).
-
- initialPictData[index] = 0;
- ++index;
-
- // Store the ctSize (-1 == 0 entries. Unused for direct pixmaps anyway).
-
- initialPictData[index] = -1;
- ++index;
-
- // Store the source rectangle at source resolution.
-
- initialPictData[index] = drawRect.top;
- ++index;
- initialPictData[index] = drawRect.left;
- ++index;
- initialPictData[index] = drawRect.bottom;
- ++index;
- initialPictData[index] = drawRect.right;
- ++index;
-
- // Store the destination rectangle at source resolution.
-
- initialPictData[index] = drawRect.top;
- ++index;
- initialPictData[index] = drawRect.left;
- ++index;
- initialPictData[index] = drawRect.bottom;
- ++index;
- initialPictData[index] = drawRect.right;
- ++index;
-
- // Store the transfer mode (ditherCopy).
-
- initialPictData[index] = ditherCopy;
- ++index;
-
- // The number of bytes we've got to write is index *2 (since
- // we bumped index at every word we stored). Empirically, this
- // comes out to 122 bytes, which explains the 122 bytes in
- // WriteStartOfPICTFile and the 61 words allocated for
- // initialPictData. If you change the data that's written into
- // this file, make sure you update those two values!!
- //
- // Write out the updated data.
-
- index *= 2;
- anErr = FSWrite(curFileRefNum, &index, initialPictData);
-
- SetFPosFailed:
- SendFinalDataFailed:
- WordAlignFailed:
- GetEOFFailed:
- FlushBuffersFailed:
-
- return anErr;
- }
-
-
- /* -----------------------------------------------------------------------
-
- WriteBlankLines is a routine used to add blank lines to our output.
- We use this to add "skipped over" lines to our output from
- SD_RasterDataIn. Since we're printing to a file, we need to add the
- white space as bands of white data.
-
- ----------------------------------------------------------------------- */
-
- static OSErr WriteBlankLines(long numBlankLinesToDo, gxRectangle *bandRect)
- {
- OSErr anErr = noErr;
- long line, aByte, lineLength;
- unsigned char *blankLine, *whichByte;
-
- // Record some "blank lines" in our file. NOTE: This assumes we output 24-bit RGB data.
-
- if (numBlankLinesToDo > 0)
- {
- // Create a pointer to hold one white (0xFF, 0xFF, 0xFF…) line.
-
- lineLength = 3 * ((bandRect->right >>16) - (bandRect->left >> 16));
- blankLine = (unsigned char *) NewPtrSys(lineLength);
- anErr = MemError();
- nrequire(anErr, NewPtrSys_Failed);
-
- // Make it white.
-
- for (aByte = 0, whichByte = blankLine; aByte < lineLength; aByte++, whichByte++)
- *whichByte = 0xFF;
-
- // Write it to the file as many times as necessary, then dispose of our pointer.
-
- for (line = 0; line < numBlankLinesToDo; line++)
- anErr = Send_GXBufferData((Ptr) blankLine, lineLength, gxNoBufferOptions);
-
- DisposePtr((Ptr) blankLine);
- }
-
- NewPtrSys_Failed:
- return anErr;
- }
-
-
-
-
-